package com.kotlin.dongdong.framework.ormlite

import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteException
import android.text.TextUtils
import android.util.Log
import com.j256.ormlite.field.DatabaseField
import com.j256.ormlite.table.DatabaseTable
import java.lang.reflect.Field
import java.util.ArrayList
import java.util.HashMap

/**
 * Created by dongdong on 2018/2/2.
 */
class DataBaseUpTools {

    class SqlItem {
        internal var sql: String? = null
        internal var column: String? = null
    }

    companion object {
        val TAG: String = "DataBaseUpTools"

        fun upGradeTable(db: SQLiteDatabase, dbName: String, clazz: Class<*>) {
            val tableName: String = getTableName(clazz)
            Log.i(TAG, "tableName=========:" + tableName)
            if (!TextUtils.isEmpty(tableName) && !TextUtils.isEmpty(dbName)) {
                val desc = "select * from $tableName limit 1"
                var cursor: Cursor? = null
                if (db != null) {
                    try {
                        cursor = db.rawQuery(desc, null)
                    } catch (e: SQLiteException) {
                        Log.e(TAG, e.toString())
                        if (cursor != null) {
                            cursor.close()
                            cursor = null
                        }
                    }

                }

                if (cursor != null) {
                    val oldColumns = cursor.columnNames
                    val newColumns = getFieldsSQL(clazz)

                    Log.i(TAG, clazz.toString() + "oldColumns :" + oldColumns + "\n newColumns: " + newColumns)
                    if (oldColumns != null && oldColumns.size > 0) {
                        if (newColumns != null && newColumns.size > 0) {
                            for (temp in newColumns) {
                                if (!TextUtils.isEmpty(temp)) {
                                    val index = temp.indexOf(" ")
                                    if (index != -1) {
                                        val newColumnName = temp.substring(0, index)
                                        if (!TextUtils.isEmpty(newColumnName)) {
                                            var isMatch = false
                                            for (old in oldColumns) {
                                                if (newColumnName == old) {
                                                    isMatch = true
                                                    break
                                                }
                                            }
                                            if (!isMatch) {
                                                var sql: String = "ALTER TABLE $tableName ADD $temp"
                                                if (sql.indexOf(",") != -1) {
                                                    sql = sql.replace(",", ";")
                                                }
                                                Log.i(TAG, "ALTER TABLE: " + sql)
                                                db!!.execSQL(sql)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    cursor.close()
                }

            }
        }

        fun getTableName(clazz: Class<*>): String {
            var tableName = ""
            var databaseTable: DatabaseTable = clazz.getAnnotation(DatabaseTable::class.java)
            tableName = databaseTable.tableName
            if (!tableName!!.isEmpty()) {
                return tableName
            }
            if (null != clazz) {
                var className: String = clazz.getName();
                if (!TextUtils.isEmpty(className)) {
                    var index: Int = className.lastIndexOf(".")
                    if (index != -1) {
                        tableName = className.substring(index + 1)
                    } else {
                        tableName = className
                    }
                }
            }
            return tableName
        }

        private fun getFieldsSQL(claz: Class<*>?): ArrayList<String>? {
            var list: ArrayList<String>? = null
            if (claz != null) {
                val map = getDatabaseFields(claz)
                if (map != null && map.size > 0) {
                    val iterator = map.entries.iterator()
                    if (iterator != null) {
                        while (iterator.hasNext()) {
                            val entry = iterator.next()
                            if (entry != null) {
                                val key = entry.key
                                val item = entry.value
                                val typeSQL = item.sql
                                val columnName = item.column

                                var sql = columnName
                                sql += " "
                                sql += typeSQL
                                sql += " "
                                sql += getDatabaseFieldSQL(key)
                                sql += ","
                                if (list == null) {
                                    list = ArrayList()
                                }

                                list.add(sql!!)
                            }
                        }
                    }
                }
            }

            return list
        }


        fun getDatabaseFields(claz: Class<*>?): HashMap<DatabaseField, SqlItem>? {
            var map: HashMap<DatabaseField, SqlItem>? = null
            if (claz != null) {
                var clazz: Class<*> = claz
                while (clazz != Any::class.java) {
                    val fields = clazz.declaredFields
                    if (fields != null && fields.size > 0) {
                        for (field in fields) {
                            if (field != null) {
                                val dbField = field.getAnnotation<DatabaseField>(DatabaseField::class.java)
                                if (dbField != null) {
                                    var columnName = dbField.columnName
                                    if (TextUtils.isEmpty(columnName)) {
                                        columnName = field.name
                                    }

                                    if (map == null) {
                                        map = HashMap()
                                    }

                                    if (TextUtils.isEmpty(columnName)) {
                                        continue
                                    }
                                    val typeSQL = getTypeSQL(field)
                                    if (TextUtils.isEmpty(typeSQL)) {
                                        continue
                                    }

                                    val item = SqlItem()
                                    item.sql = typeSQL
                                    item.column = columnName

                                    map.put(dbField, item)
                                }
                            }
                        }
                    }
                    clazz = clazz.superclass
                }
            }
            return map
        }

        fun getTypeSQL(field: Field?): String {
            var sql = ""
            if (field != null) {
                if (field.type == Long::class.javaPrimitiveType
                        || field.type == Int::class.javaPrimitiveType
                        || field.type == Short::class.javaPrimitiveType
                        || field.type == Byte::class.javaPrimitiveType
                        || field.type == Boolean::class.javaPrimitiveType
                        || field.type == Char::class.javaPrimitiveType) {
                    sql = "integer"
                } else if (field.type == Float::class.javaPrimitiveType || field.type == Double::class.javaPrimitiveType) {
                    sql = "real"
                } else if (field.type == String::class.java) {
                    sql = "text"
                } else {//全部用gjson转换成字符串
                    sql = "text"
                }
            }
            return sql
        }

        fun getDatabaseFieldSQL(dbField: DatabaseField?): String {
            var sql = ""
            if (dbField != null) {
                if (dbField.id || dbField.generatedId) {
                    sql += "primary key  "
                } else if (dbField.generatedId) {
                    sql += "primary key autoincrement "
                } else {
                    if (!dbField.canBeNull) {
                        sql += "not null "
                    }
                    if (dbField.unique) {
                        sql += "unique "
                    }
                }
            }

            Log.i(TAG, dbField.toString() + "  getDatabaseFieldSQL: " + sql)
            return sql
        }

    }

}